package com.jakewharton.rxbinding4.component;

import com.jakewharton.rxbinding4.RecordingObserver;
import io.reactivex.rxjava3.functions.Consumer;
import ohos.aafwk.ability.delegation.AbilityDelegatorRegistry;
import ohos.agp.components.Component;
import ohos.agp.components.DirectionalLayout;
import ohos.app.Context;
import org.junit.Test;

import static ohos.agp.components.Component.FOCUS_ENABLE;
import static org.junit.Assert.*;

public class RxComponentTest {
    private final Context context = AbilityDelegatorRegistry.getAbilityDelegator().getAppContext();
    private final Component view = new Component(context);

    @Test
    public void clicks() {
        RecordingObserver<Object> o = new RecordingObserver<>();
        RxComponent.clicks(view).subscribe(o);
        o.assertNoMoreEvents(); // No initial value.

        view.callOnClick();
        assertNotNull(o.takeNext());

        view.callOnClick();
        assertNotNull(o.takeNext());

        o.dispose();

        view.callOnClick();
        o.assertNoMoreEvents();
    }

    @Test public void focusChanges() {
        // We need a parent which can take focus from our view when it attempts to clear.
        DirectionalLayout parent = new DirectionalLayout(context);
        parent.setFocusable(FOCUS_ENABLE);
        parent.addComponent(view);

        view.setFocusable(FOCUS_ENABLE);

        RecordingObserver<Boolean> o = new RecordingObserver<>();
        RxComponent.focusChanges(view).subscribe(o);
        assertFalse(o.takeNext());

        view.requestFocus();
        assertTrue(o.takeNext());

        view.clearFocus();
        assertFalse(o.takeNext());

        o.dispose();

        view.requestFocus();
        o.assertNoMoreEvents();
    }

    @Test public void layoutChanges() {
        RecordingObserver<Object> o = new RecordingObserver<>();
        RxComponent.layoutChanges(view).subscribe(o);
        o.assertNoMoreEvents();

        view.postLayout();
        assertNotNull(o.takeNext());

        view.postLayout();
        o.assertNoMoreEvents();

        o.dispose();
        view.postLayout();
        o.assertNoMoreEvents();
    }

    @Test public void longClicks() {
        // We need a parent because long presses delegate to the parent.
        DirectionalLayout parent = new DirectionalLayout(context);
        parent.addComponent(view);

        RecordingObserver<Object> o = new RecordingObserver<>();
        RxComponent.longClicks(view).subscribe(o);
        o.assertNoMoreEvents(); // No initial value.

        view.executeLongClick();
        assertNotNull(o.takeNext());

        view.executeLongClick();
        assertNotNull(o.takeNext());

        o.dispose();

        view.executeLongClick();
        o.assertNoMoreEvents();
    }

    @Test public void scrollChangeEvents() {
        RecordingObserver<ComponentScrollChangeEvent> o = new RecordingObserver<>();
        RxComponent.scrollEvents(view).subscribe(o);
        o.assertNoMoreEvents();

        view.scrollTo(1, 1);
        ComponentScrollChangeEvent event0 = o.takeNext();
        assertSame(view, event0.view());
        assertEquals(1, event0.scrollX());
        assertEquals(1, event0.scrollY());
        assertEquals(0, event0.oldScrollX());
        assertEquals(0, event0.oldScrollY());

        view.scrollTo(2, 2);
        ComponentScrollChangeEvent event1 = o.takeNext();
        assertSame(view, event1.view());
        assertEquals(2, event1.scrollX());
        assertEquals(2, event1.scrollY());
        assertEquals(1, event1.oldScrollX());
        assertEquals(1, event1.oldScrollY());

        o.dispose();
        view.scrollTo(3, 3);
        o.assertNoMoreEvents();
    }

    @Test public void clickable() throws Throwable {
        view.setClickable(true);
        Consumer<? super Boolean> action = RxComponent.clickable(view);
        action.accept(false);
        assertFalse(view.isClickable());
        action.accept(true);
        assertTrue(view.isClickable());
    }

    @Test public void enabled() throws Throwable {
        view.setEnabled(true);
        Consumer<? super Boolean> action = RxComponent.enabled(view);
        action.accept(false);
        assertFalse(view.isEnabled());
        action.accept(true);
        assertTrue(view.isEnabled());
    }

    @Test public void pressed() throws Throwable {
        view.setPressState(true);
        Consumer<? super Boolean> action = RxComponent.pressed(view);
        action.accept(false);
        assertFalse(view.isPressed());
        action.accept(true);
        assertTrue(view.isPressed());
    }

    @Test public void selected() throws Throwable {
        view.setSelected(true);
        Consumer<? super Boolean> action = RxComponent.selected(view);
        action.accept(false);
        assertFalse(view.isSelected());
        action.accept(true);
        assertTrue(view.isSelected());
    }

    @Test public void visibility() throws Throwable {
        view.setVisibility(Component.VISIBLE);
        Consumer<? super Integer> action = RxComponent.visibility(view);
        action.accept(Component.INVISIBLE);
        assertEquals(Component.INVISIBLE, view.getVisibility());
        action.accept(Component.VISIBLE);
        assertEquals(Component.VISIBLE, view.getVisibility());
    }

}